package com.stars.services.impl.mygenerate;

import com.stars.common.MyStrRegex;
import com.stars.common.ObjectCopyUtils;
import com.stars.common.base.BaseConstant;
import com.stars.common.base.ResultMsg;
import com.stars.common.enums.FieldValidTypeEnum;
import com.stars.common.enums.TableTypeEnum;
import com.stars.common.gen.GenerateCodeBtlUtils;
import com.stars.common.maps.MyMapUtils;
import com.stars.common.valid.MyException;
import com.stars.dao.mapper.mygenerate.CgFormFieldMapper;
import com.stars.entity.ListPage;
import com.stars.entity.dto.mygenerate.CgTemplateDTO;
import com.stars.entity.mygenerate.*;
import com.stars.services.mygenerate.*;
import freemarker.template.Configuration;
import freemarker.template.Template;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author csot.qhluodajie on 2019/1/8.
 */
@Slf4j
@Service
public class MyGenerateServiceImpl implements MyGenerateService {
    private final String srcMainJava = "/src/main/java/";
    private final String srcMainRes = "/src/main/resources/";
    private final String fileType = ".java";
    @Autowired
    private Configuration configuration;
    @Autowired
    private MyProjectPathConfig myProjectPathConfig;
    @Autowired
    private CgFormHeadServices cgFormHeadServices;
    @Autowired
    private CgFormFieldMapper cgFormFieldMapper;
    @Autowired
    private CgTemplateAccessServices cgTemplateAccessServicesImpl;
    @Autowired
    private CgGroupAccessServices cgGroupAccessServicesImpl;
    @Autowired
    private CgConfigAccessService cgConfigAccessServiceImpl;

    @Override
    public ResultMsg autoCodeGenerateFtl(String ids) throws Exception {

        if (StringUtils.isBlank(ids)) {
            return ResultMsg.failure("请选择一条数据！");
        }
        Map<String, String> mapMsg = new HashMap<>();
        for (String id : ids.split(BaseConstant.SPOT)) {
            //创建数据表
            //cgFormHeadServices.createDBTable(id);
            CgFormHead cgFormHead = cgFormHeadServices.findById(id);
            //更新状态
            // cgFormHead.setIsDbSynchronization("Y");
            // cgFormHeadServices.update(cgFormHead);
            mapMsg.put(cgFormHead.getTableName(), cgFormHead.getTableName());
            mapMsg.put(cgFormHead.getModuleName(), cgFormHead.getModuleName());

            TemplateTableConfig templateTableConfig = getTableType(cgFormHead);
            for (MyModulesGenerateConfig modulesGenerateConfig : myProjectPathConfig.getModulesName()) {
                List<MyModulesGenerateConfig> myModulesGenerateConfigList = myProjectPathConfig.getModulesName();
                templateTableConfig.setPackageName(modulesGenerateConfig.getPackageName() + "." + cgFormHead.getModuleName());


                //后缀
                templateTableConfig.setEntityPostfix(modulesGenerateConfig.getClassPostfix());
                //项目路径
                //包名替换
                String packageName = modulesGenerateConfig.getPackageName().replace(".", "/") + "/";
                // path: D:\\sccbv\\sccbv\\sccbv-entity\\src\\main\\java\\com\\sccbv\\entity
                String entityPath = modulesGenerateConfig.getSrcPath()
                        + packageName
                        + cgFormHead.getModuleName();
                //读取ftl生成文件
                String templateClassName = templateTableConfig.getEntityName() + templateTableConfig.getEntityPostfix();
                Map<String, Object> map = new HashMap<>();
                map.put("tc", templateTableConfig);
                map.put("ftl", modulesGenerateConfig);
                map.put("cgH", cgFormHead);
                map.put("mList", myModulesGenerateConfigList);
                freemarker(modulesGenerateConfig.getFtl(), entityPath, templateClassName + modulesGenerateConfig.getType(), map);
            }

        }
        return ResultMsg.success(mapMsg);
    }

    @Override
    public ResultMsg autoCodeBtl(String ids) throws Exception {
        if (StringUtils.isBlank(ids)) {
            return ResultMsg.failure("请选择一条数据！");
        }
        Map<String, String> mapMsg = new HashMap<>();
        for (String id : ids.split(BaseConstant.SPOT)) {
            CgFormHead cgFormHead = cgFormHeadServices.findById(id);
            //更新状态
            // cgFormHead.setIsDbSynchronization("Y");
            // cgFormHeadServices.update(cgFormHead);

            //1 表的类型,单表生成
            if (TableTypeEnum.SINGLE.getValue().equals(cgFormHead.getTableType())) {
                genFiled(cgFormHead);
            //多表生成
            } else if (TableTypeEnum.MAIN.getValue().equals(cgFormHead.getTableType())) {
                if (StringUtils.isBlank(cgFormHead.getTableInfoIds())) {
                    throw new MyException("没有从表信息");
                }
                Map<String,String> infoEntity =new HashMap<>();
                for (String infoId : cgFormHead.getTableInfoIds().split(BaseConstant.SPOT)) {
                    if (StringUtils.isBlank(infoId)) {
                        continue;
                    }
                    CgFormHead cgFormHeadInfo = cgFormHeadServices.findById(infoId);
                    if(null == cgFormHeadInfo){
                        continue;
                    }
                    infoEntity.put(cgFormHeadInfo.getEntityName(),cgFormHeadInfo.getTableName());
                    genFiled(cgFormHeadInfo);
                }
                //从表保存参数 实体+addJson
                cgFormHead.setTableInfoNames(MyMapUtils.mapKeyToStrArray(infoEntity));
                genFiled(cgFormHead);
            //从表不生成
            } else if (TableTypeEnum.INFO.getValue().equals(cgFormHead.getTableType())) {
                throw new MyException("从表不生成");
            } else {
                genFiled(cgFormHead);
            }
        }
        return ResultMsg.success();
    }


    @Override
    public ResultMsg autoDbGenerate(String ids) throws Exception {
        if (StringUtils.isBlank(ids)) {
            return ResultMsg.failure("请选择一条数据！");
        }
        for (String id : ids.split(BaseConstant.SPOT)) {
            //创建数据表
            cgFormHeadServices.createDBTable(id);
        }
        return ResultMsg.success();
    }

    @Override
    public void freemarker(String ftlName, String outFilePath, String generateName, Map<String, Object> map) throws Exception {
        Writer out = null;
        try {
            // 加载模版文件
            Template template = configuration.getTemplate("mygenerate/" + ftlName);
            // step3 生成数据
            String pathName = outFilePath;
            File file = new File(pathName);
            if (!file.exists()) {
                file.mkdirs();
            }
            File docFile = new File(outFilePath + "/" + generateName);
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));
            // step5 输出文件
            template.process(map, out);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw e;
        } finally {
            try {
                if (null != out) {
                    out.flush();
                }
            } catch (Exception e2) {
                throw e2;
            }
        }
    }

    @Override
    public TemplateTableConfig getTableType(CgFormHead cgFormHead) throws Exception {

        TemplateTableConfig templateTableConfig = new TemplateTableConfig();
        templateTableConfig.setTableName(cgFormHead.getTableName());
        // String entityName = MyStrRegex.underLineBackFirstCharToUpperCase(cgFormHead.getTableName());
        templateTableConfig.setEntityName(cgFormHead.getEntityName());
        templateTableConfig.setTableComment(cgFormHead.getContent());
        templateTableConfig.setModuleName(cgFormHead.getModuleName());
        //表字段查询配制
        List<TemplateFieldConfig> templateFieldConfigList = new LinkedList<>();
        List<CgFormField> cgFormFieldList = cgFormFieldMapper.findTableId(cgFormHead.getId());
        Map<String, String> fieldValidMap = new HashMap<>();
        for (CgFormField cgFormField : cgFormFieldList) {
            TemplateFieldConfig templateFieldConfig = new TemplateFieldConfig();
            ObjectCopyUtils.copyPropertiesIf(cgFormField, templateFieldConfig);
            String name = cgFormField.getName();
            templateFieldConfig.setName(name);
            templateFieldConfig.setIsNull(cgFormField.getNotEmpty());
            //去掉下划线后字母大写
            templateFieldConfig.setFieldName(MyStrRegex.underLineBackFirstCharToUpperCase(name));
            templateFieldConfig.setDbType(cgFormField.getType());
            String type = MyStrRegex.fistNameToUpperCase(cgFormField.getType());
            //除了int , 其他类型第一个字母大写
            if ("text".equals(cgFormField.getType())) {
                type = "String";
            }
            if ("datetime".equals(cgFormField.getType())) {
                type = "Date";
            }
            if ("int".equals(cgFormField.getType())) {
                type = "Integer";
            }
            //如果是验证唯一，添加
            if (FieldValidTypeEnum.VALID_UNIQUE_CONSTRAINTS.getValue().equals(cgFormField.getFieldValidType())) {
                fieldValidMap.put(MyStrRegex.underLineBackFirstCharToUpperCase(name), cgFormField.getName());
            }
            if("AUTO_CODE".equals(cgFormField.getFieldValidType())){
                templateTableConfig.setAutoCode("AUTO_CODE");
            }
            templateFieldConfig.setType(type);
            templateFieldConfig.setComment(cgFormField.getText());
            templateFieldConfigList.add(templateFieldConfig);
        }
        templateTableConfig.setFieldValid(MyMapUtils.mapKeyToStrArray(fieldValidMap));
        templateTableConfig.setTemplateFieldConfigList(templateFieldConfigList);

        return templateTableConfig;


    }

    /**
     * 获取配制
     *
     * @param tempGroupId 配制id
     * @return
     */
    private CgConfigEntity getConfig(String tempGroupId) {
        //获取配制
        if (StringUtils.isBlank(tempGroupId)) {
            throw new MyException("没有选择生成模板参数");
        }
        return cgConfigAccessServiceImpl.selectById(tempGroupId);
    }

    //生成
    private void genFiled(CgFormHead cgFormHead) throws Exception {
        if (null == cgFormHead) {
            throw new MyException("没有选择生成的数据");
        }
        //配制信息
        CgConfigEntity cgConfigEntity = getConfig(cgFormHead.getTempGroupId());
        //模板组
        CgGroupEntity cgGroupEntity = cgGroupAccessServicesImpl.selectById(cgConfigEntity.getTempId());
        if (cgGroupEntity == null) {
            throw new MyException("没有选择生成模板参数");
        }
        //模板集合
        List<CgTemplateDTO> tempList = cgTemplateAccessServicesImpl.selList(cgGroupEntity.getId());
        TemplateTableConfig templateTableConfig = getTableType(cgFormHead);
        if (null != tempList) {
            StringBuilder logInfo = new StringBuilder("\n================生成地址========================\n");
            CgConfigEntity finalCgConfigEntity = cgConfigEntity;
            tempList.forEach(t -> {
                if("GridJson".equals(t.getLastName()) && !TableTypeEnum.MAIN.getValue().equals(cgFormHead.getTableType())){
                    return;
                }
                //outPath ="E:/stars/stars-common/src/main/java/"
                StringBuilder outFilePath = new StringBuilder(finalCgConfigEntity.getCodePath() + "/" + t.getCodePath());
                String packageName = t.getCodePack().replace(".", "/") + "/" + cgFormHead.getModuleName() + "/";
                if (fileType.equals(t.getTempSuffix())) {
                    outFilePath.append(srcMainJava);
                } else {
                    outFilePath.append(srcMainRes);
                }
                outFilePath.append(packageName);
                String outFileName = cgFormHead.getEntityName() + t.getLastName() + t.getTempSuffix();
                Map<String, Object> map = new HashMap<>();
                map.put("cgH", cgFormHead);
                map.put("cf", finalCgConfigEntity);
                map.put("temp", t);
                map.put("tempList", tempList);
                map.put("fieldList", templateTableConfig.getTemplateFieldConfigList());
                map.put("config", templateTableConfig);
                logInfo.append("outFilePath：" + outFilePath + "\n");
                logInfo.append("生成名称：" + outFileName + "\n");
                GenerateCodeBtlUtils.generateCodeBtl(t.getTempCode(), outFilePath.toString(), outFileName, map);
            });
            log.info(logInfo.toString());
            log.info("===============================================");
        }

    }
}
